<?php
/*
Plugin Name: Delete Duplicate Posts Revisited
Plugin Script: delete-duplicate-posts.php
Plugin URI: http://js.gg
Description: Get rid of duplicate blog posts on your blog! How embarrassing, eh? This handy plugin runs in the background and automatically deletes duplicate posts as they occur!
Version: 3.0b
Author: Jeff Steinport
Author URI: http://js.gg
Min WP Version: 3.0
Max WP Version: 3.3

== Changelog ==

= 3.0b =
* New release, modified from the bloated original "Delete Duplicate Posts"
* All advertising and annoying links removed
* Cleaner interface
* Automatically runs as a cron job
* More options added for frequency of cron run

*/

if (!class_exists('delete_duplicate_posts')) {
    class delete_duplicate_posts {
        var $optionsName = 'delete_duplicate_posts_options';
        var $localizationDomain = "delete_duplicate_posts";
        var $thispluginurl = '';
        var $thispluginpath = '';
        var $options = array();
        function delete_duplicate_posts(){$this->__construct();}
        function __construct(){
            $locale = get_locale();
            $mo = dirname(__FILE__) . "/languages/" . $this->localizationDomain . "-".$locale.".mo";
            load_textdomain($this->localizationDomain, $mo);

            //"Constants" setup
            $this->thispluginurl = PLUGIN_URL . '/' . dirname(plugin_basename(__FILE__)).'/';
            $this->thispluginpath = PLUGIN_PATH . '/' . dirname(plugin_basename(__FILE__)).'/';

            $this->getOptions();
      // Setting filters, actions, hooks....
			add_action("admin_menu", array(&$this,"admin_menu_link"));
			register_activation_hook(__FILE__,array(&$this,"install"));
			add_action('admin_head', array(&$this,"admin_register_head"));
			add_action('init', array(&$this,"init_function"));
			add_action('ddp_cron', array(&$this,"cleandupes"));
			add_filter('cron_schedules', array(&$this,"my_corn_schedules"));

        }

/* function parse_query($val) {

  $var  = html_entity_decode($var);
  $var  = explode('&', $var);
  $arr  = array();

  foreach($var as $val)
   {
    $x          = explode('=', $val);
    $arr[$x[0]] = $x[1];
   }
  unset($val, $x, $var);
  return $arr;
 }
 */

// This function adds more options for the frequency of the cron job.

function my_corn_schedules(){
	return array(
		'in_per_minute' => array(
			'interval' => 60,
			'display' => 'In every Minute'
		),
		'in_per_ten_minute' => array(
			'interval' => 60 * 10,
			'display' => 'In every two Minutes'
		),
		'three_hourly' => array(
			'interval' => 60 * 60 / 3,
			'display' => 'Once every 20 minutes'
		)
	);
}


function init_function() {
    $plugpage = strtolower($_GET['page']);
    if ($plugpage=='delete-duplicate-posts.php') {
		wp_enqueue_script( 'jquery' );
    	wp_enqueue_script( 'jquery-ui-core' );
    	wp_enqueue_script( 'jquery-ui-tabs' );
    }
}


function cleandupes($manualrun='0') {
	if (!$this->options['ddp_running'] ) {
		$this->options['ddp_running']=TRUE;
		global $wpdb,$wp_version,$wp_locale,$current_blog,$wp_rewrite;

		$table_name = $wpdb->prefix . "posts";

		$limit=$this->options['ddp_limit'];
		if (!$limit<>'') $limit=10; //defaults to 10!

		if ($manualrun=='1') $limit=9999;

		$order=$this->options['ddp_keep'];
		if (($order<>'oldest') OR ($order<>'latest')) { // verify default value has been set.
			$this->options['ddp_keep']='oldest';
			}

		if ($order=='oldest') $minmax="MIN(id)";
		if ($order=='latest') $minmax="MAX(id)";

		$query="select bad_rows.*
	    from $table_name as bad_rows
	    inner join (
	    select post_title,id, $minmax as min_id
	    from $table_name
	    WHERE (
	    (
	    `post_status` = 'published'
	    )
	    OR (
	    `post_status` = 'publish'
	    ) AND `post_type` = 'post'
	    )
	    group by post_title
	    having count(*) > 1
	    ) as good_rows on good_rows.post_title = bad_rows.post_title
	    and good_rows.min_id <> bad_rows.id limit 50;";


	    $dupes = $wpdb->get_results($query);
	    $dupescount = count($dupes);
	    $resultnote='';
	    $dispcount=0;
	    if ($dupescount>0) {
		    foreach ($dupes as $dupe) {
		    	$postid=$dupe->ID;
		    	$title=$this->truncatestring($dupe->post_title,35);
		    	$perma=get_permalink($postid);
		    	if ($postid<>''){
		    		$custom_field_keys = get_post_custom_keys($postid);
		    		foreach ( $custom_field_keys as $key => $value ) {
		    			delete_post_meta($postid, $key, '');

		    		}
		    		$result = wp_delete_post($postid);
		    		if (!$result) {
		    			$this->log(" !! Problem deleting post $postid - $perma !!");
		    		}
		    		else {
		    			$dispcount++;
		    			$this->log("Deleted post '$title' (Post ID:$postid) and all related META keys.");
		    		}
		    	}
		    }
		}


		if ($dispcount>0) {

			$this->log("A total of $dispcount duplicate posts were deleted!");
			if ( function_exists('w3tc_pgcache_flush') ) {
	    		w3tc_pgcache_flush();
	 	 	  	$this->log("W3 Total Cache pages flushed");
		    }
		    if (function_exists('wp_cache_clear_cache() ')) {
		    	wp_cache_clear_cache();
		    	$this->log("WP Super Cache pages flushed");
		    }
		}

	unset($wpdb);
	unset($wp_version);
	unset($wp_locale);
	unset($current_blog);
	unset($wp_rewrite);
	$this->options['ddp_running']=FALSE;

	if ($dupescount==0) {
			$this->log("No duplicates to delete.");
		}

	}
}

//END cleandupes()

function admin_register_head() {
    $plugpage = strtolower($_GET['page']);
    if ($plugpage=='delete-duplicate-posts.php') {
    	wp_admin_css();
	wp_enqueue_script( 'common' );
	wp_enqueue_script( 'jquery-color' );
	wp_print_scripts('editor');
	if (function_exists('add_thickbox')) add_thickbox();
	wp_print_scripts('media-upload');
	if (function_exists('wp_tiny_mce')) wp_tiny_mce();
	wp_admin_css();
	wp_enqueue_script('utils');
	do_action("admin_print_styles-post-php");
	do_action('admin_print_styles');
    	$siteurl = get_option('siteurl');
   	$url = $siteurl . '/wp-content/plugins/' . basename(dirname(__FILE__)) . '/delete-duplicate-posts.css';
    	echo "<link rel='stylesheet' type='text/css' href='$url' />\n";
    }
}




function log($text) {
	global $wpdb;
	$table_name_log = $wpdb->prefix . "delete-duplicate-posts_log";
	$text= 	gmdate("(d M Y H:i:s e)", time()) ." - ". mysql_real_escape_string($text);
	$query = "INSERT INTO `$table_name_log` (note)
					  VALUES (
					  '$text'
					  )";
	$success = mysql_query($query);
	unset($query);
	unset($success);
}

function install () {
		global $wpdb;
		if ( file_exists(ABSPATH . 'wp-admin/includes/upgrade.php') ) {
		    require_once(ABSPATH . '/wp-admin/includes/upgrade.php');
		} else { // Wordpress <= 2.2
		    require_once(ABSPATH . 'wp-admin/upgrade-functions.php');
		}
		$table_name_log = $wpdb->prefix . "delete-duplicate-posts_log";
		dbDelta("CREATE TABLE `$table_name_log` (
			  `id` int(11) NOT NULL auto_increment,
			  `note` varchar(255) NOT NULL default '',
			  UNIQUE KEY `id` (`id`)
		) ENGINE=MyISAM  DEFAULT CHARSET=latin1;");
		$this->log("Log database created.");
		$this->saveAdminOptions();
		wp_clear_scheduled_hook('ddp_cron');
}

function getOptions() {
            //Don't forget to set up the default options
            if (!$theOptions = get_option($this->optionsName)) {
                $theOptions = array('default'=>'options');
                update_option($this->optionsName, $theOptions);
            }
            $this->options = $theOptions;
}

function saveAdminOptions(){
	return update_option($this->optionsName, $this->options);
}


function truncatestring($string, $del) {
	$len = strlen($string);
	if ($len > $del) {
		$new = substr($string,0,$del)."...";
		return $new;
	}
		  else return $string;
}

function admin_menu_link() {
	add_management_page('Delete Duplicate Posts', 'Delete Duplicate Posts', 8, basename(__FILE__), array(&$this,'admin_options_page'));
	add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'filter_plugin_actions'), 10, 2 );
}

function filter_plugin_actions($links, $file) {
	$settings_link = '<a href="tools.php?page=' . basename(__FILE__) . '">' . __('Settings') . '</a>';
	array_unshift( $links, $settings_link ); // before other links
	return $links;
}

/* function to_hour_string($MM) {
	$MM=floor($MM/60);
        $Hour=floor($MM/60);
        $Min=($MM%60);
        If($Hour>0)
        {
                $str = $Hour." hour";
                if ($Hour > 1)
                        $str .= "s";
                if ($Min > 0)
                        $str .= " ".$Min." minute";
                if ($Min > 1)
                        $str .= "s";
        }
        else if ($Min > 0)
        {
                $str = " ".$Min." minute";
                if ($Min > 1)
                        $str .= "s";
        }
        else
        {
                $str = "-";
        }
        return $str;
}
*/

function admin_options_page() {

// DELETE NOW
	if ( (wp_verify_nonce($_POST['_wpnonce'], 'ddp-clean-now')) && ($_POST['deleteduplicateposts_delete'] ) ){
		$this->cleandupes(1); // use the value 1 to indicate it is being run manually.
	}



// RUN NOW!!
/*	if($_POST['ddp_runnow']){
		if (! wp_verify_nonce($_POST['_wpnonce'], 'ddp-update-options') ) die('Whoops! Some error occured, try again, please!');

		if ( function_exists('current_user_can') && current_user_can('edit_plugins')) {
			$search4dupes=true; // remember that we are searching for dupes! .. is used later on in this function as to not disturb the layout
		}
	}

*/

// SAVING OPTIONS
	if($_POST['delete_duplicate_posts_save']){
		if (! wp_verify_nonce($_POST['_wpnonce'], 'ddp-update-options') )
			die('Whoops! There was a problem with the data you posted. Please go back and try again.');
		$this->options['ddp_enabled'] = ($_POST['ddp_enabled']=='on')?true:false;
		$this->options['ddp_keep'] = mysql_real_escape_string($_POST['ddp_keep']);
   		$this->options['ddp_limit'] = mysql_real_escape_string($_POST['ddp_limit']);
		$this->options['ddp_freq'] = mysql_real_escape_string($_POST['ddp_freq']);

   		if ($this->options['ddp_enabled'] ){
			wp_clear_scheduled_hook('ddp_cron');
			wp_schedule_event(time(), 'three_hourly', 'ddp_cron');
		} else {
			wp_clear_scheduled_hook('ddp_cron');
		}

		$this->saveAdminOptions();

		echo '<div class="updated"><p>Your changes were successfully saved!</p></div>';
	}

// CLEARING THE LOG
	if($_POST['ddp_clearlog']){
		if (! wp_verify_nonce($_POST['_wpnonce'], 'ddp_clearlog_nonce') ) die('Whoops! Some error occured, try again, please!');
		global $wpdb;
		$table_name_log = $wpdb->prefix . "delete-duplicate-posts_log";
		$wpdb->query ("TRUNCATE `$table_name_log`;");
		echo '<div class="updated"><p>The log was cleared</p></div>';
		unset($wpdb);
	}

	global $wpdb;

// Check for if update is necessary... And then runs the install function if needed.
	$table_name = $wpdb->prefix . "delete-duplicate-posts_log";
	if($wpdb->get_var("show tables like '$table_name'") != $table_name) {
		$this->install();
	}

	$table_name = $wpdb->prefix . "posts";

	$pluginfo=get_plugin_data(__FILE__);
	$version=$pluginfo['Version'];
	$name=$pluginfo['Name'];
	$siteurl = get_option('siteurl');
		?>

	<div class="wrap" style="font-family:arial;">
		<div id="tabs" style="font-family:arial;">
		<h2>Delete Duplicate Posts Reloaded<span id="cpgreen"> v <?php echo $version; ?></span></h2>
		<br class="clear" />

<?php
//	}
	?>

	<br class="clear" />
		<ul>
			<li><a href="#dashboard"><?php _e('Dashboard', $this->localizationDomain); ?></a></li>
			<li><a href="#configuration"><?php _e('Configuration', $this->localizationDomain); ?></a></li>
			<li><a href="#log"><?php _e('Log', $this->localizationDomain); ?></a></li>
			<li><a href="#help"><?php _e('Help', $this->localizationDomain); ?></a></li>
		</ul>

		<script type="text/javascript">
		jQuery(function(){

		    // Tabs
		    jQuery('#tabs').tabs();

		    //hover states on the static widgets
		    jQuery('#dialog_link, ul#icons li').hover(
		    	function() { $(this).addClass('ui-state-hover'); },
		    	function() { $(this).removeClass('ui-state-hover'); }
		    );

		});
		</script>

<div id="dashboard" style="font-family:arial;">

	<h3>Dashboard</h3>
	<?php
		if ($this->options['ddp_enabled'] ) {
			$nextscheduled = wp_next_scheduled('ddp_cron');
			if (!$nextscheduled<>'') { // plugin active, but the cron needs to be activated also..
				echo "Cron has not been activated. Setting up cron now...";
				wp_clear_scheduled_hook('ddp_cron');
				wp_schedule_event(time(), 'three_hourly', 'ddp_cron');
				$nextscheduled = wp_next_scheduled('ddp_cron');

			}

			$nexttime=date('l jS \of F Y H:i ',$nextscheduled);

		}	else {
			wp_clear_scheduled_hook('ddp_cron');
		}

// Status check

	$order=$this->options['ddp_keep'];
	if ($order=='oldest') $minmax="MIN(id)";
	if ($order=='latest') $minmax="MAX(id)";

		$query="select bad_rows.*
	    from wp_posts as bad_rows
	    inner join (
	    select post_title,id, $minmax as min_id
	    from wp_posts
	    WHERE (
	    (
	    `post_status` = 'published'
	    )
	    OR (
	    `post_status` = 'publish'
	    ) AND `post_type` = 'post'
	    )
	    group by post_title
	    having count(*) > 1
	    ) as good_rows on good_rows.post_title = bad_rows.post_title
	    and good_rows.min_id <> bad_rows.id limit 50;";

			$dupes = $wpdb->get_results($query);

			$dupescount = count($dupes);

/* echo "Duplicates: ".$dupescount."<br />";

$blabla = array(&$this,"cleandupes");
echo $blabla."<br />";

$table_name = $wpdb->prefix . "posts";
echo $table_name."<br />";
$order=$this->options['ddp_keep'];
echo "Order:".$order."<br />";
echo "minmax:".$minmax."<br />";

echo "Running? ".$this->options['ddp_running'];

*/

if ($dupescount) {

?>
			<div class="ui-state-error ui-corner-all" style="padding: 0pt 0.7em;margin-left:6em;margin-right:6em;">
					<p><span class="ui-icon ui-icon-alert" style="float: left; margin-right: 0.3em;"></span>
					<strong>Warning</strong>: I have discovered a total of <strong><?php echo $dupescount; ?></strong> duplicate blog posts!</p>
				<h3>Top 10</h3>

<p><strong>You can either delete these posts now by clicking on the Delete All Duplicates button below, or you can wait until the next automatic check at: <?php echo $nexttime?></strong><em>(Current server time is <?php echo date('l jS \of F Y H:i ',time())?></p>
<?php

		// lets show them some of them
		$query="select bad_rows.*
	    from wp_posts as bad_rows
	    inner join (
	    select post_title,id, $minmax as min_id
	    from wp_posts
	    WHERE (
	    (
	    `post_status` = 'published'
	    )
	    OR (
	    `post_status` = 'publish'
	    ) AND `post_type` = 'post'
	    )
	    group by post_title
	    having count(*) > 1
	    ) as good_rows on good_rows.post_title = bad_rows.post_title
	    and good_rows.min_id <> bad_rows.id limit 10;";


			$dupes = $wpdb->get_results($query);

			$plugurl=WP_CONTENT_URL . '/plugins/' .plugin_basename(__FILE__) ;
			echo '<table class="widefat post" cellspacing="0">';

			echo '<thead><tr><th>Post title</th></thead>';
			echo '<tbody>';
			foreach ($dupes as $dupe) {
				$postid=$dupe->ID;

				$title=$this->truncatestring($dupe->post_title,120);
				echo "<tr><td><a href='".get_permalink($postid)."' target='_blank'>".$title."</a></td></tr>";
			}
			echo '</tbody>';
			echo "</table>";
			?>
	<form method="post" id="ddp_runcleannow">
	<?php wp_nonce_field('ddp-clean-now'); ?>
	<p align="center"><input type="submit" name="deleteduplicateposts_delete" class="button-primary" value="Delete All Duplicates" /></p>
</form>
			<?php
			echo "</div>";

	} else { // no dupes found!

		?>
	<div class="ui-state-highlight ui-corner-all" style="margin-top: 20px; padding: 0pt 0.7em;">
		<p><span class="ui-icon ui-icon-info" style="float: left; margin-right: 0.3em;"></span>
		I have just checked, and you have no detected duplicate posts right now.</p>
		<p>
		<?php

		$nextscheduled = wp_next_scheduled('ddp_cron');

		if ($nextscheduled) echo "You have enabled CRON, so I am running automatically. Relax, I'll take care of everything...";
	if ($nextscheduled) echo _e("<p>Next automatic check: <strong>$nexttime</strong><em>(Current server time is ".date('l jS \of F Y H:i ',time()).")</em></p>", $this->localizationDomain);

		if (!$nextscheduled) echo "<strong>Cron is currently disabled. This means that duplicate posts will not automatically be deleted. To enable automatic deletion, go to the Configuration tab and enable cron.</strong>";
		?>
	</p>


	</div>

	<?php
	}
	?>

</div>

<div id="configuration">
	<h3><?php _e('Configuration', $this->localizationDomain); ?></h3>
	<form method="post" id="delete_duplicate_posts_options">

	<?php wp_nonce_field('ddp-update-options'); ?>

	<table width="100%" cellspacing="2" cellpadding="5" class="form-table">

	<th colspan=2><h4><?php _e('Automatic (cron) Settings', $this->localizationDomain); ?></h4></th>
	<tr valign="top">
	<th><label for="ddp_enabled"><?php _e('Enable cron?:', $this->localizationDomain); ?></label></th><td><input type="checkbox" id="ddp_enabled" name="ddp_enabled" <?php if ($this->options['ddp_enabled']==true){echo 'checked="checked"';} ?>>
	<p><em><?php _e('Clean duplicates automatically', $this->localizationDomain); ?></em></p>
        </td>
        </tr>

 	<th><label for="ddp_keep"><?php _e('Which posts to keep?:', $this->localizationDomain); ?></label></th><td>

 	<select name="ddp_keep" id="ddp_keep" style="width:150px;font-family:arial;">
 		<option value="oldest" <?php if ($this->options['ddp_keep']=='oldest') echo "selected"; ?>>Keep oldest post </option>
	 	<option value="latest" <?php if ($this->options['ddp_keep']=='latest') echo "selected"; ?>>Keep latest post </option>
 	</select>

	<p><em><?php _e('Keep the oldest or the latest version of duplicates? Default is keeping the oldest, and deleting any subsequent duplicate posts', $this->localizationDomain); ?></em></p>
        </td>
        </tr>

<th><label for="ddp_freq">Frequency of cron job:</label></th><td>

 	<select name="ddp_freq" id="ddp_freq" style="width:150px;font-family:arial;">
 		<option value="in_per_minute" <?php if ($this->options['ddp_freq']=='in_per_minute') echo "selected"; ?>>Every Minute </option>
 		<option value="in_per_ten_minute" <?php if ($this->options['ddp_freq']=='in_per_ten_minute') echo "selected"; ?>>Every 10 Minutes </option>
 		<option value="three_hourly" <?php if ($this->options['ddp_freq']=='three_hourly') echo "selected"; ?>>Every 20 Minutes </option>
 		<option value="hourly" <?php if ($this->options['ddp_freq']=='hourly') echo "selected"; ?>>Every Hour </option>
 	</select>

	<p><em><?php _e('Run the duplicate delete posts job how often?', $this->localizationDomain); ?></em></p>
        </td>
        </tr>

	<tr valign="top">
        <th><label for="ddp_limit"><?php _e('Limit to maximum :', $this->localizationDomain); ?></label></th><td><select name="ddp_limit" style="width:150px;font-family:arial;">
	<?php
	for($x = 1; $x <= 8; $x++) {
		$val=($x*25);
		echo "<OPTION VALUE='$val' ";
		if ($this->options['ddp_limit']==$val) echo "selected";
		echo ">$val </OPTION>";
	}
	?>
	</select> <?php _e(' duplicates.', $this->localizationDomain); ?>
	<p><em><?php _e('Limiting is a good idea if your site is on a busy server.', $this->localizationDomain); ?></em></p>
	</td>
	</tr>

	<th colspan=2><input type="submit" class="button-primary" name="delete_duplicate_posts_save" value="<?php _e('Save Settings', $this->localizationDomain); ?>" style="font-family:arial;" /></th>
        </tr>
	</table>
	</form>
</div>

<div id="log">
	<h3><?php _e('The Log', $this->localizationDomain); ?></h3>
	<textarea rows="30" class="large-text" name="ddp_log" id="ddp_log" style="font-family:courier;font-size:11px;"><?php 
		$table_name_log = $wpdb->prefix . "delete-duplicate-posts_log";
	$query = "SELECT * FROM `".$table_name_log."` order by `id` ASC";
	$loghits = $wpdb->get_results($query, ARRAY_A);
	if ($loghits){
		foreach ($loghits as $hits) {
		echo $hits['note']."\n";
		}
	}
	unset($loghits);
	unset($query);
	unset($table_name_log);
	?></textarea>
	<p>
        <form method="post" id="ddp_clearlog">
        <?php wp_nonce_field('ddp_clearlog_nonce'); ?>

        <input type="submit" name="ddp_clearlog" value="Reset log" />
	</form>
	</p>
</div>

<div id="help">

	<p>Welcome to Delete Duplicate Posts Reloaded. I modified thus plugin to remove all of the annoying advertisements.</p>

	<p>USE AT YOUR OWN RISK. I modified this plugin for my own needs, so I have no idea if it will work for you too.</p>

	<p><strong>BACKUP YOUR DATABASE BEFORE ENABLING THIS PLUGIN.</strong></p>

</div>

</div>

<?php

        }

  } //End Class
}

if (class_exists('delete_duplicate_posts')) {
    $delete_duplicate_posts_var = new delete_duplicate_posts();
}
?>

